<script setup>
import { ElMessage } from "element-plus";
import { nextTick, onMounted, ref, watch } from "vue";
import { useClipboard } from "@vueuse/core";
import { parameters } from "@/api/index.js";
import { cloneDeep, isEmpty, toString } from "lodash-es";
import { useAiStore } from "@/stores/aiStore";
import { marked } from "marked";
import "github-markdown-css";
import {
  clearSession,
  cqxczwyAiConfig,
  createSession,
  deleteSession,
} from "@/api/ai";

const props = defineProps({
  isDialog: {
    type: Boolean,
    default: false,
  },
});

const aiDataStore = useAiStore();

// 发送消息
const search = ref("");
// 全部消息
const messageData = ref([]);
const messageIndex = ref(1);
// 消息是否接收完成
const isMessageFinish = ref(true);

const prompt =
  "我是“渝小育”AI助手 可以向您提供准确的教育统计信息及多跨事件信息";

onMounted(async () => {
  if (!props.isDialog) {
    messageData.value.push({
      message: prompt,
    });
    return;
  }

  await getCqxczwyAiConfig();
  await getCreateSession();
});

const aiConfig = ref();
async function getCqxczwyAiConfig() {
  const { data } = await cqxczwyAiConfig({
    name: '"渝小育"AI数智人',
    status: "0",
  });
  aiConfig.value = data;
}

const uniqueCode = ref();
async function getCreateSession() {
  const { data } = await createSession(
    {
      agentCode: aiConfig.value.agentCode,
      agentVersion: aiConfig.value.agentVersion,
    },
    {
      Authorization: aiConfig.value.appKey,
    }
  );
  uniqueCode.value = data.uniqueCode;
  messageData.value.push({
    message: prompt,
  });
}

async function getChatMessages() {
  const resp = await fetch(
    `${window.location.origin}/xlm-gateway-ftlzsf/sfm-api-gateway/gateway/agent/api/run`,
    {
      method: "post",
      body: JSON.stringify({
        stream: true,
        delta: true,
        sessionId: uniqueCode.value,
        message: {
          text: search.value,
          metadata: {},
          attachments: [],
        },
      }),
      headers: {
        "Content-Type": "application/json",
        Authorization: aiConfig.value.appKey,
      },
      // responseType: "stream", // 重要：流式响应
    }
  );

  const reader = resp.body.getReader();
  const decoder = new TextDecoder();
  let buffer = ""; // 缓冲不完整的数据块

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true }); // 可能包含不完整数据

    const lines = buffer.split("\n");
    // 保留未处理的行（最后一行可能不完整）
    buffer = lines.pop() || "";

    for (const line of lines) {
      const trimmedLine = line.trim();
      if (!trimmedLine.startsWith("data:")) continue;

      try {
        // 提取并解析 JSON
        const jsonStr = trimmedLine.replace("data:", "");
        const eventData = JSON.parse(jsonStr);
        processEvent(eventData);
      } catch (e) {
        // JSON解析失败，保留剩余数据到下一次处理
        console.log(e);
        break;
      }
    }
  }
}

const contentBuffer = ref("");
const html = ref("");
const render = new marked.Renderer();
marked.setOptions({
  renderer: render, // 这是必填项
  gfm: true, // 启动类似于Github样式的Markdown语法
  pedantic: false, // 只解析符合Markdwon定义的，不修正Markdown的错误
  sanitize: false, // 原始输出，忽略HTML标签（关闭后，可直接渲染HTML标签）
});

function processEvent(eventData) {
  if (
    eventData.end === false &&
    eventData.content.length != 0 &&
    !isMessageFinish.value
  ) {
    const answer = eventData.content.map((item) => item.text.value);

    contentBuffer.value += answer;
    html.value = marked.parse(contentBuffer.value);
    // 异步方式渲染

    // console.log("Generated HTML:", html.value); // 调试输出

    // 响应式更新数组
    messageData.value.splice(messageIndex.value, 1, {
      message: html.value,
    });
  } else if (eventData.end === true) {
    html.value = "";
    contentBuffer.value = "";
    messageIndex.value += 1;
    isMessageFinish.value = true;
  }
}

async function handleSearch() {
  if (!search.value || !isMessageFinish.value || messageData.value.length === 0)
    return;
  messageData.value.push({ message: search.value });

  getChatMessages();
  search.value = "";
  messageIndex.value += 1;
  messageData.value[messageIndex.value] = { message: "思考中。。。" };
  isMessageFinish.value = false;
}

// 终止接收消息
async function handleClearSession() {
  await clearSession(
    {
      sessionId: uniqueCode.value,
    },
    {
      Authorization: aiConfig.value.appKey,
    }
  );
  isMessageFinish.value = true;
  html.value = "";
  contentBuffer.value = "";
  messageIndex.value += 1;
}

defineExpose({ reset });

function reset() {
  aiDataStore.fullScreenChange = 1;
  search.value = "";
  messageData.value = [];
  html.value = "";
  messageIndex.value = 1;
  contentBuffer.value = "";
  aiDataStore.isFullDialog = false;
  delSession();
}

async function delSession() {
  await deleteSession(
    {
      sessionId: uniqueCode.value,
    },
    {
      Authorization: aiConfig.value.appKey,
    }
  );
}

function handleDelete() {
  search.value = "";
}

const lastMessage = ref([]);
watch(
  messageData,
  () => {
    nextTick(() => {
      if (lastMessage.value.length > 0) {
        lastMessage.value[lastMessage.value.length - 1].scrollIntoView({
          behavior: "smooth",
          block: "end",
          inline: "nearest",
        });
      }
    });
  },
  { deep: true }
);

const { copy } = useClipboard();

function handleCopy(value) {
  const data = value.replace(/<[^>]*>/g, "");
  copy(data);
  ElMessage({ type: "success", message: "复制成功" });
}
</script>

<template>
  <div class="ai">
    <div class="info">
      <div
        v-for="(item, index) in messageData"
        :key="index"
        class="info-box"
        ref="lastMessage"
        :style="{ justifyContent: index % 2 !== 0 ? 'flex-end' : 'start' }"
      >
        <img
          v-if="index % 2 === 0"
          src="@/assets/images/aiPhoto.png"
          class="info-box-i"
        />
        <div
          class="info-box-c"
          :class="index % 2 !== 0 ? 'tipLeft' : 'tipRight'"
          :style="{ fontSize: aiDataStore.isFullDialog ? '22px' : '16px' }"
        >
          <div class="info-box-c-c markdown-body" v-html="item.message"></div>
          <div v-if="item.source" class="info-box-c-b">
            来源：{{ item.source }}
          </div>
          <div
            class="info-box-c-btn"
            v-if="
              index % 2 === 0 && index !== 0 && item.message !== '思考中。。。'
            "
          >
            <img
              src="@/assets/images/copy.png"
              class="info-box-c-btn-c"
              @click="handleCopy(item.message)"
            />
          </div>
        </div>
        <img
          v-if="index % 2 !== 0"
          src="@/assets/images/mPhoto.png"
          class="info-box-i"
        />
      </div>
    </div>
    <div
      class="context"
      :style="{ fontSize: aiDataStore.isFullDialog ? '18px' : '12px' }"
    >
      *内容由AI生成仅供参考
    </div>
    <div
      class="ipt"
      :style="{ height: aiDataStore.isFullDialog ? '80px' : '64px' }"
    >
      <img
        src="@/assets/images/delete.png"
        :class="aiDataStore.isFullDialog ? 'ipt-del-large' : 'ipt-del'"
        @click="handleDelete"
      />
      <el-input
        :class="aiDataStore.isFullDialog ? 'ipt-search-large' : 'ipt-search'"
        v-model="search"
        placeholder="来问点什么吧（回车默认模型搜索）"
        @keyup.enter.native="handleSearch"
        :disabled="!isMessageFinish"
      ></el-input>
      <el-button
        v-if="isMessageFinish"
        class="ipt-btn"
        :style="{ width: aiDataStore.isFullDialog ? '100px' : '80px' }"
        type="primary"
        @click="handleSearch"
        :disabled="messageData.length === 0"
      >
        发送
      </el-button>
      <el-button
        v-else
        class="ipt-btn"
        :style="{ width: aiDataStore.isFullDialog ? '100px' : '80px' }"
        type="primary"
        @click="handleClearSession"
      >
        停止
      </el-button>
    </div>
  </div>
</template>

<style lang="less" scoped>
.ai {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  .info {
    flex: 1;
    width: 100%;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    padding: 16px 20px 8px;
    gap: 16px;
    .info-box {
      width: 100%;
      display: flex;
      gap: 16px;
      .info-box-i {
        width: 50px;
        height: 50px;
      }
      .info-box-c {
        max-width: 80%;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: space-between;
        padding: 12px;
        font-size: 16px;
        color: #c9e9f8;

        border-radius: 6px;
        position: relative;
        .info-box-c-c {
          width: 100%;
          flex: 1;
          // display: flex;
          // align-items: center;
        }
        .info-box-c-b {
          width: 100%;
          display: flex;
          justify-content: end;
          align-items: center;
          font-size: 12px;
          color: rgba(201, 233, 248, 0.6);
        }
        .info-box-c-btn {
          position: absolute;
          left: 0;
          bottom: -40px;
          .info-box-c-btn-c {
            width: 30px;
            height: 30px;
            cursor: pointer;
          }
        }
      }
      .tipRight {
        background: #175784;
        // background: #fff;
        min-width: 120px;
        &:before {
          content: "";
          display: block;
          border: 10px solid;
          position: absolute;
          top: 13px;
          left: -18px;
          width: 0;
          height: 0;
          border-color: transparent #175784 transparent transparent;
        }
      }
      .tipLeft {
        background: #064c96;
        // background: #fff;
        &:after {
          content: "";
          display: block;
          border: 10px solid;
          position: absolute;
          top: 13px;
          right: -18px;
          width: 0;
          height: 0;
          border-color: transparent transparent transparent #064c96;
        }
      }
    }
  }
  .context {
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 12px;
    color: rgba(255, 255, 255, 0.5);
    margin-top: 6px;
  }
  .ipt {
    width: calc(100% - 16px);
    height: 64px;
    margin: 8px;
    background: linear-gradient(
      180deg,
      rgba(20, 133, 185, 0.3) 0%,
      #0f6faf 100%
    );
    border-radius: 8px 8px 8px 8px;
    border: 1px solid;
    border-image: linear-gradient(
        180deg,
        rgba(34, 161, 196, 0.7),
        rgba(34, 196, 188, 0.1)
      )
      1 1;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px;
    .ipt-del {
      width: 26px;
      height: 26px;
      cursor: pointer;
    }
    .ipt-del-large {
      width: 52px;
      height: 52px;
      cursor: pointer;
    }
    .ipt-search {
      flex: 1;
      height: 100%;
      ::v-deep .el-input__wrapper {
        background: rgba(14, 51, 91, 0.8);
        border-radius: 4px 4px 4px 4px;
        box-shadow: none;
        .el-input__inner {
          color: #ffffff;
        }
      }
    }
    .ipt-search-large {
      flex: 1;
      height: 100%;
      ::v-deep .el-input__wrapper {
        background: rgba(14, 51, 91, 0.8);
        border-radius: 4px 4px 4px 4px;
        box-shadow: none;
        .el-input__inner {
          color: #ffffff;
          font-size: 20px;
        }
      }
    }
    .ipt-btn {
      width: 80px;
      height: 100%;
      // background: #1669b6;
      // box-shadow: inset 0px 0px 20px 0px rgba(96, 207, 255, 0.8);
      // border-radius: 4px 4px 4px 4px;
      // border: 1px solid #09d6ff;
      font-size: 18px;
      // color: #ffffff;
      display: flex;
      align-items: center;
      justify-content: center;
      line-height: normal;
      // cursor: pointer;
    }
  }

  ::-webkit-scrollbar {
    width: 0.75rem; /* 设置滚动条宽度 */
  }

  ::-webkit-scrollbar-thumb {
    background-color: #0858ab; /* 设置滚动条滑块颜色 */
    border-radius: 0.375rem; /* 设置滑块的圆角 */
  }

  ::-webkit-scrollbar-track {
    background: rgba(255, 255, 255, 0.1); /* 设置滚动条背景色 */
    border-radius: 0.375rem; /* 设置滚动条背景的圆角 */
  }

  .markdown-body {
    color: inherit;
    background-color: inherit;
    font-size: inherit;
  }
  ::v-deep .markdown-body table th,
  ::v-deep .markdown-body table td {
    color: #353530;
  }
  ::v-deep .markdown-body blockquote {
    color: #c9e9f8;
  }
}
</style>
